Package vg.userInterface.jgraphx

Source Code of vg.userInterface.jgraphx.JGraphView

package vg.userInterface.jgraphx;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Observer;
import java.util.Set;

import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;

import com.mxgraph.analysis.mxGraphAnalysis;
import com.mxgraph.analysis.mxICostFunction;
import com.mxgraph.layout.mxIGraphLayout;
import com.mxgraph.layout.mxParallelEdgeLayout;
import com.mxgraph.model.mxCell;
import com.mxgraph.swing.mxGraphComponent;
import com.mxgraph.swing.mxGraphOutline;
import com.mxgraph.swing.handler.mxKeyboardHandler;
import com.mxgraph.swing.handler.mxRubberband;
import com.mxgraph.swing.util.mxMorphing;
import com.mxgraph.util.mxConstants;
import com.mxgraph.util.mxEvent;
import com.mxgraph.util.mxEventObject;
import com.mxgraph.util.mxPoint;
import com.mxgraph.util.mxUndoManager;
import com.mxgraph.util.mxUndoableEdit;
import com.mxgraph.util.mxUtils;
import com.mxgraph.util.mxEventSource.mxIEventListener;
import com.mxgraph.util.mxUndoableEdit.mxUndoableChange;
import com.mxgraph.view.mxCellState;
import com.mxgraph.view.mxGraph;
import com.mxgraph.view.mxGraphView;

import vg.core.AModel;
import vg.core.AUserInterface;
import vg.core.IGraphView;
import vg.core.VisualGraph;
import vg.core.graph.SubGraph;
import vg.core.request.IUIRequestOwner;
import vg.core.request.UIRequestGoToInAIF;
import vg.core.request.UIRequestOpenSubGraph;
import vg.core.storableGraph.StorableAttribute;
import vg.core.storableGraph.StorableEdge;
import vg.core.storableGraph.StorableSubGraph;
import vg.core.storableGraph.StorableVertex;
import vg.userInterface.core.IGraphLayoutManager;
import vg.userInterface.swingComponents.ZoomComboBox;

/**
* This class is wrapper to jgraphx library It contains swing components which draw graph and minimap
*
* @author dkolbin
*/

public class JGraphView implements IGraphView {
  private mxGraphComponent graphComponent = null;
  private mxGraphOutline graphOutline = null;
  private mxUndoManager undoManager;
  private mxIEventListener scaleTracker = null;
  private final StorableSubGraph subGraph;
  private AUserInterface userInterface = null;
  private IUIRequestOwner requestOwner;
  private mxGraph currentGraph;
  private JPopupMenu popup;
  private JMenu connectorPopup;
  // -------------------------------------------
  private HashMap<mxCell, Integer> subgraphsid;
  private HashMap<mxCell, HashMap<StorableAttribute, Boolean>> edgeAttributes;
  private HashMap<mxCell, HashMap<StorableAttribute, Boolean>> vertexAttributes;
  private HashMap<Integer, Connection> connections;
  private int graphId = -1;
  // -------------------------------------------
  private ArrayList<Observer> observers;
  private final AModel model;
  private IGraphLayoutManager layoutManager;
  // Title of graph view
  private String title = null;

  private ActionListener settingListner = new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
      Object parent = currentGraph.getDefaultParent();
      currentGraph.getModel().beginUpdate();
      for (Object cell : currentGraph.getChildCells(parent)) {
        mxCellState state = currentGraph.getView().getState(cell);
        state.setStyle(currentGraph.getCellStyle(cell));
        currentGraph.updateCellSize(cell);
      }
      currentGraph.getModel().endUpdate();
      currentGraph.repaint();
    }
  };
  // -------------------------------------------------------------------------
  // private constructor
  // -------------------------------------------------------------------------
  private JGraphView(AUserInterface userInterface, final StorableSubGraph subGraph) {
    // set model, which may use for getting different information.
    if (userInterface != null) {
      this.model = userInterface.getModel();
    } else {
      this.model = null;
    }
    this.subGraph = subGraph;
    this.observers = new ArrayList<Observer>();
    this.userInterface = userInterface;
    this.layoutManager = this.userInterface.getGraphLayoutManager();
    this.edgeAttributes = new HashMap<mxCell, HashMap<StorableAttribute, Boolean>>();
    this.vertexAttributes = new HashMap<mxCell, HashMap<StorableAttribute, Boolean>>();
    this.connections = new HashMap<Integer, Connection>();
    // ---------------------------------------
    buildTitleAndGraphId(); // find graphId, graph view's title
    // ---------------------------------------
    currentGraph = new mxGraph();
    undoManager = new mxUndoManager();
    // deny clone cells
    currentGraph.setCellsCloneable(false);
    currentGraph.setGridEnabled(false);
    currentGraph.setCellsDeletable(false);
    currentGraph.setHtmlLabels(true);
    currentGraph.setMultigraph(true);
    // deny changing edge targets
    currentGraph.setCellsDisconnectable(false);
    // deny edge which doesn't connect with some cells
    currentGraph.setAllowDanglingEdges(false);
    currentGraph.setCellsEditable(false);
    currentGraph.setGridSize(4);
   
    currentGraph.getModel().addListener(mxEvent.UNDO, undoHandle);
    currentGraph.getView().addListener(mxEvent.UNDO, undoHandle);

    // Set default style for vertexes
    currentGraph.setStylesheet(JGraphSettings.getStylesheet());
    JGraphSettings.addListner(settingListner);

    this.requestOwner = new IUIRequestOwner() {
      public void callRequestOwner(Object obj) {
        // TODO
      }
    };

    guiSetup();
  }

  // -------------------------------------------------------------------------
  // public constructors
  // -------------------------------------------------------------------------

  /**
   * Construct new JGraphView object from another, which contain only those vertexes and edges, which have subGraph. New view will be
   * zoomed. This constructor also copy all visualized attributes from old view into new.
   *
   * @param view
   *            - old view
   * @param subGraph
   *            - subgraph,
   */
  public JGraphView(JGraphView view, StorableSubGraph subGraph) {
    this(view.userInterface, subGraph);
    this.userInterface = view.userInterface;
    // ---------------------------------------
    Object parent = this.currentGraph.getDefaultParent();
    List<StorableVertex> vertexes = this.subGraph.getVertices();
    Object[] cells;
    if (view.isSelected())
      cells = view.currentGraph.getSelectionCells();
    else
      cells = view.currentGraph.getChildVertices(view.currentGraph.getDefaultParent());
    HashMap<String, mxCell> id2vert = new HashMap<String, mxCell>();
    this.subgraphsid = new HashMap<mxCell, Integer>();
    currentGraph.getModel().beginUpdate();
    for (Object cell : cells) {
      if (((mxCell) cell).isVertex()) {
        for (StorableVertex v : vertexes) {
          if (((mxCell) cell).getId().equals("v" + v.getStorableId())) {
            mxCell c = (mxCell) cell;

            mxCell c2 = (mxCell) currentGraph.insertVertex(parent, c.getId(), c.getValue(), c.getGeometry().getX(), c
                .getGeometry().getY(), c.getGeometry().getWidth(), c.getGeometry().getHeight(), c.getStyle());

            id2vert.put(c.getId(), c2);
            if (view.subgraphsid.get(c) != null) {
              this.subgraphsid.put((mxCell) c2, view.subgraphsid.get(c));
            }
            HashMap<StorableAttribute, Boolean> m = view.vertexAttributes.get(c);
            HashMap<StorableAttribute, Boolean> m2 = new HashMap<StorableAttribute, Boolean>();
            for (StorableAttribute s : m.keySet()) {
              m2.put(s, m.get(s));
            }
            vertexAttributes.put(c2, m2);
            break;
          }

        }
      }
    }

    cells = view.currentGraph.getAllEdges(cells);
    for (StorableEdge edge : this.subGraph.getEdges()) {
      for (Object cell : cells) {
        mxCell c = (mxCell) cell;
        mxCell source = (mxCell) c.getSource();
        mxCell target = (mxCell) c.getTarget();
        if (source == null || target == null)
          continue;
        if (!source.getId().equals("v" + edge.getStorableSource().getStorableId())
            || !target.getId().equals("v" + edge.getStorableTarget().getStorableId()))
          continue;
        Object source2 = id2vert.get(source.getId());
        Object target2 = id2vert.get(target.getId());
        if (source2 != null && target2 != null) {
          mxCell c2 = (mxCell) currentGraph.insertEdge(parent, c.getId(), c.getValue(), source2, target2, c.getStyle());
          c2.setGeometry(c.getGeometry());
          HashMap<StorableAttribute, Boolean> m = view.edgeAttributes.get(c);
          HashMap<StorableAttribute, Boolean> m2 = new HashMap<StorableAttribute, Boolean>();
          for (StorableAttribute s : m.keySet()) {
            m2.put(s, m.get(s));
          }
          edgeAttributes.put(c2, m2);
          break;
        }
      }
    }
    currentGraph.getModel().endUpdate();
    double x = 0;
    double y = 0;

    cells = currentGraph.getChildCells(currentGraph.getDefaultParent());
    boolean initialize = false;
    for (Object cell : cells) {
      mxCellState state = currentGraph.getView().getState(cell);
      if (!initialize) {
        x = state.getLabelBounds().getX();
        y = state.getLabelBounds().getY();
        initialize = true;
      }
      if (state.getLabelBounds().getX() < x)
        x = state.getLabelBounds().getX();

      if (state.getLabelBounds().getY() < y)
        y = state.getLabelBounds().getY();
    }
    if (initialize)
      currentGraph.moveCells(currentGraph.getChildCells(currentGraph.getDefaultParent()), -x, -y);

    double zoomfactor = currentGraph.getView().getScale();
    double zoomfactorx = zoomfactor / currentGraph.getView().getGraphBounds().getWidth() * view.graphComponent.getWidth();
    double zoomfactory = zoomfactor / currentGraph.getView().getGraphBounds().getHeight() * view.graphComponent.getHeight();

    currentGraph.getView().setScale(Math.max(Math.min(zoomfactorx, zoomfactory), zoomfactor));
  }

  /**
   * Standard constructor for JGraphView which load
   *
   * @param g
   *            - subgraph, which should be showed
   */
  public JGraphView(final StorableSubGraph g, final AUserInterface userInterface) {
    this(userInterface, g);
    this.loadGraph();
  }

  // -------------------------------------------------------------------------
  // public methods
  // -------------------------------------------------------------------------
  public JComponent getGraphRepresentation() {
    return graphComponent;
  }

  public JComponent getMiniMap() {
    return graphOutline;
  }

  public void setZoom(String scale) {
    if (scale.equals("Actual size")) {
      graphComponent.zoomActual();
    } else {
      try {
        scale = scale.replace("%", "");
        graphComponent.zoomTo(Double.parseDouble(scale) / 100, true);
      } catch (Exception ex) {
        JOptionPane.showMessageDialog(null, ex.getMessage());
      }
    }
  }

  public void SetEnableZoomComboToGraphView(boolean enable, final ZoomComboBox zoomCombo) {
    if (enable) {
      scaleTracker = new mxIEventListener() {
        public void invoke(final Object sender, final mxEventObject evt) {
          if (!SwingUtilities.isEventDispatchThread()) {
            SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                invoke(sender, evt);
              }
            });
            return;
          }
          final mxGraphView view = graphComponent.getGraph().getView();
          double scale = view.getScale();
          if (scale > 100) {
            scale = 100;
            graphComponent.zoomTo(scale, true);
          }
          zoomCombo.setSelectedItem(Math.round(100 * scale) + "%");

        }
      };

      graphComponent.getGraph().getView().addListener(mxEvent.SCALE, scaleTracker);
      graphComponent.getGraph().getView().addListener(mxEvent.SCALE_AND_TRANSLATE, scaleTracker);
      scaleTracker.invoke(null, null);
    } else {
      graphComponent.getGraph().getView().removeListener(scaleTracker);
    }
  }

  public void zoomIn() {
    graphComponent.zoomIn();
  }

  public void zoomOut() {
    graphComponent.zoomOut();
  }

  public void redo() {
    undoManager.redo();
  }

  public void undo() {
    undoManager.undo();
  }

  public StorableSubGraph getStorableSubGraph() {
    return (this.subGraph);
  }

  public SubGraph getSubGraph() {
    return (this.subGraph.getSubGraph());
  }

  public void showAttributes(final Set<String> vertexAttr, final Set<String> edgeAttr) {
    Object[] cells;
    if (currentGraph.isSelectionEmpty()) {
      cells = currentGraph.getChildCells(currentGraph.getDefaultParent());
    } else {
      cells = currentGraph.getSelectionCells();
    }
    currentGraph.getModel().beginUpdate();

    // vertexes-------------------------------
    for (Object cell : cells) {
      Map<StorableAttribute, Boolean> attrs = this.vertexAttributes.get(cell);
      if (attrs != null) {
        for (StorableAttribute a : attrs.keySet()) {
          attrs.put(a, new Boolean(false));
        }
        for (StorableVertex v : subGraph.getVertices()) {
          if (((mxCell) cell).getId().equals("v" + v.getStorableId())) {
            String ss = "";
            for (String str : vertexAttr) {
              String s = null;
              Collection<StorableAttribute> listAttribute = v.getAttributes();
              if (listAttribute != null) {
                for (StorableAttribute bufAttriute : listAttribute) {
                  if (bufAttriute.getName().equals(str)) {
                    s = bufAttriute.getValue();
                    attrs.put(bufAttriute, new Boolean(true));
                  }
                }
                if (s != null)
                  if (str.equals("name"))
                    ss = "<b>" + s.replaceAll("\\n", "<br>")+ "</b>" + "<br>" + ss;
                  else
                    ss += "<b>" + str + "</b>" + ":" + s.replaceAll("\\n", "<br>") + "<br>";
              }
            }
            if (ss.length() > 0) {
              ss = "<html>" +
//              "<center><font color=black size=2><b>&lt;" + v.getId() + "&gt;</b></font></center>" +
                ss + "</html>";
            }
            ((mxCell) cell).setValue(ss);
            currentGraph.updateCellSize(cell);
            break;
          }
        }

      }
      currentGraph.getView().getState(cell).setStyle(currentGraph.getCellStyle(cell));
    }
    // edges----------------------------------
    for (Object cell : cells) {
      Map<StorableAttribute, Boolean> attrs = this.edgeAttributes.get(cell);
      if (attrs != null) {
        for (StorableAttribute a : attrs.keySet()) {
          attrs.put(a, new Boolean(false));
        }
        String ss = "";
        for (StorableEdge e : subGraph.getEdges()) {
          if (((mxCell) cell).getId().equals("e" + e.getStorableId())) {
            for (String str : edgeAttr) {
              String s = null;
              Collection<StorableAttribute> listAttribute = e.getStorableAttributes();
              if (listAttribute != null) {
                for (StorableAttribute bufAttriute : listAttribute) {
                  if (bufAttriute.getName().equals(str)) {
                    s = bufAttriute.getValue();
                    attrs.put(bufAttriute, new Boolean(true));
                  }
                }
              }
              if (s != null)
                ss += "<b>" + str + "</b>" + ":" + s.replaceAll("\\n", "<br>") + "<br>";
            }
            ((mxCell) cell).setValue("<html>" + ss + "</html>");
            break;
          }
        }

      }
    }
    currentGraph.getModel().endUpdate();

    double x = 0;
    double y = 0;
    cells = currentGraph.getChildCells(currentGraph.getDefaultParent());
    for (Object cell : cells) {
      mxCellState state = currentGraph.getView().getState(cell);
      if (state != null) {
        currentGraph.getView().updateLabelBounds(state);
        if (state.getLabelBounds().getX() < x)
          x = state.getLabelBounds().getX();
        if (state.getLabelBounds().getY() < y)
          y = state.getLabelBounds().getY();
      }
    }
    if (x != 0 || y != 0)
      currentGraph.moveCells(currentGraph.getChildCells(currentGraph.getDefaultParent()), -x, -y);
    currentGraph.repaint();   
  }

  public StorableSubGraph getSelectionSubGraph() {
    if (!isSelected())
      return null;
    ArrayList<StorableVertex> vertexes = new ArrayList<StorableVertex>();
    Object[] cells = currentGraph.getSelectionCells();
    if (cells.length == 0) {
      return (null);
    }
    for (Object cell : cells) {
      if (((mxCell) cell).isVertex()) {
        for (StorableVertex v : subGraph.getVertices()) {
          if (((mxCell) cell).getId().equals("v" + v.getStorableId())) {
            vertexes.add(v);
            break;
          }
        }
      }
    }
    List<StorableEdge> edges = getAllEdgesBeetweenVertexes(vertexes);
    return (new StorableSubGraph(subGraph.getName(), vertexes, edges, subGraph.isDirected()));

  }

  public boolean isSelected() {
    return !this.currentGraph.isSelectionEmpty();
  }

  public Map<StorableAttribute, Boolean> getEdgeAttributes() {
    HashMap<StorableAttribute, Boolean> map = new HashMap<StorableAttribute, Boolean>();
    Object[] cells;
    if (currentGraph.isSelectionEmpty()) {
      cells = currentGraph.getChildEdges(currentGraph.getDefaultParent());
    } else {
      cells = currentGraph.getSelectionCells();
    }
    for (Object cell : cells) {
      Map<StorableAttribute, Boolean> attrs = this.edgeAttributes.get((mxCell) cell);
      if (attrs != null)
        map.putAll(attrs);
    }

    return map;
  }

  public Map<StorableAttribute, Boolean> getVertexAttributes() {
    HashMap<StorableAttribute, Boolean> map = new HashMap<StorableAttribute, Boolean>();
    Object[] cells;
    if (currentGraph.isSelectionEmpty()) {
      cells = currentGraph.getChildVertices(currentGraph.getDefaultParent());
    } else {
      cells = currentGraph.getSelectionCells();
    }

    for (Object cell : cells) {
      Map<StorableAttribute, Boolean> attrs = this.vertexAttributes.get((mxCell) cell);
      if (attrs != null) {
        map.putAll(attrs);
      }
    }
    return map;
  }

  public void executeLayout() {
    currentGraph.getModel().beginUpdate();
    Object layout = layoutManager.getDefaultLayout().getLayout(this);
    if (layout instanceof mxIGraphLayout) {
      mxIGraphLayout l = (mxIGraphLayout) layout;
      l.execute(currentGraph.getDefaultParent());
    }

    if (layoutManager.isAnimated()) {
      mxMorphing morph = new mxMorphing(graphComponent, 20, 1.2, 20);
      morph.addListener(mxEvent.DONE, new mxIEventListener() {
        public void invoke(Object sender, mxEventObject evt) {
          currentGraph.getModel().endUpdate();
        }

      });
      morph.startAnimation();
    } else {
      currentGraph.getModel().endUpdate();
    }
    mxParallelEdgeLayout paralLay = new mxParallelEdgeLayout(currentGraph);
    paralLay.execute(currentGraph.getDefaultParent());
    // sometimes layout can put vertex out of minimap, that should fix it
    double x = 0, y = 0;
    boolean init = false;
    for (Object o : currentGraph.getChildCells(currentGraph.getDefaultParent())) {
      mxCell cell = (mxCell) o;
      if (cell.isVertex()) {
        if (cell.getGeometry().getX() < x || !init)
          x = cell.getGeometry().getX();
        if (cell.getGeometry().getY() < y || !init)
          y = cell.getGeometry().getY();
      } else if (cell.getGeometry().getPoints() != null)
        for (mxPoint point : cell.getGeometry().getPoints()) {
          if (point.getX() < x || !init)
            x = point.getX();
          if (point.getY() < y || !init)
            y = point.getY();
        }
      init = true;
    }
    if (init)
      currentGraph.moveCells(currentGraph.getChildCells(currentGraph.getDefaultParent()), -x, -y);
  }

  public void setInvisibleEdges(Set<Integer> edgeIds) {
    Object parent = currentGraph.getDefaultParent();
    Object[] cells = currentGraph.getChildEdges(parent);
    ArrayList<Object> visiblecells = new ArrayList<Object>();
    ArrayList<Object> invisiblecells = new ArrayList<Object>();
    for (Object cell : cells) {
      if (cell instanceof mxCell) {
        boolean inv = false;
        mxCell c = (mxCell) cell;
        for (StorableEdge e : subGraph.getEdges()) {
          if (c.getId().equals("e" + e.getStorableId()) && edgeIds.contains(Integer.valueOf(e.getStorableId()))) {
            invisiblecells.add(c);
            inv = true;
            break;
          }
        }
        if (!inv)
          visiblecells.add(c);
      }
    }
    mxUtils.setCellStyles(currentGraph.getModel(), invisiblecells.toArray(), mxConstants.STYLE_OPACITY, "20");
    mxUtils.setCellStyles(currentGraph.getModel(), invisiblecells.toArray(), mxConstants.STYLE_TEXT_OPACITY, "20");
    mxUtils.setCellStyles(currentGraph.getModel(), visiblecells.toArray(), mxConstants.STYLE_OPACITY, "100");
    mxUtils.setCellStyles(currentGraph.getModel(), visiblecells.toArray(), mxConstants.STYLE_TEXT_OPACITY, "100");
  }

  public void setInvisibleVertices(Set<Integer> vertexIds) {
    Object parent = currentGraph.getDefaultParent();
    Object[] cells = currentGraph.getChildVertices(parent);
    ArrayList<Object> visiblecells = new ArrayList<Object>();
    ArrayList<Object> invisiblecells = new ArrayList<Object>();
    for (Object cell : cells) {
      if (cell instanceof mxCell) {
        boolean inv = false;
        mxCell c = (mxCell) cell;
        for (StorableVertex v : subGraph.getVertices()) {
          if (c.getId().equals("v" + v.getStorableId()) && vertexIds.contains(v.getStorableId())) {
            invisiblecells.add(c);
            inv = true;
            break;
          }
        }
        if (!inv)
          visiblecells.add(c);
      }
    }
    mxUtils.setCellStyles(currentGraph.getModel(), invisiblecells.toArray(), mxConstants.STYLE_OPACITY, "20");
    mxUtils.setCellStyles(currentGraph.getModel(), invisiblecells.toArray(), mxConstants.STYLE_TEXT_OPACITY, "20");
    mxUtils.setCellStyles(currentGraph.getModel(), visiblecells.toArray(), mxConstants.STYLE_OPACITY, "100");
    mxUtils.setCellStyles(currentGraph.getModel(), visiblecells.toArray(), mxConstants.STYLE_TEXT_OPACITY, "100");
  }

  // -------------------------------------------------------------------------
  public void addObserver(Observer o) {
    synchronized (this.observers) {
      this.observers.add(o);
    }
  }

  public void deleteAllObservers() {
    synchronized (this.observers) {
      this.observers.clear();
    }
  }

  public void deleteObserver(Observer o) {
    synchronized (this.observers) {
      this.observers.remove(o);
    }
  }

  mxGraph getGraph() {
    return currentGraph;
  }

  public void showCycles(final StorableVertex vertex) {
    ArrayList<Object> cicle = findPath(vertex, vertex);
    if (cicle != null && cicle.size() > 1) {
      currentGraph.setSelectionCells(cicle);
    } else {
      VisualGraph.windowMessage.infoMessage("Cicle was not found with vertex " + vertex.getId(), "Cicle messsage");
    }
  }

  public void showCriticalPath(final StorableVertex source, final StorableVertex target, final boolean maximum, final String attrName) {
    mxCell from = null;
    mxCell to = null;
    Object parent = currentGraph.getDefaultParent();
    Object[] cells = currentGraph.getChildVertices(parent);
    for (Object c : cells) {
      if (c instanceof mxCell) {
        mxCell cell = (mxCell) c;
        if (cell.getId().equals("v" + source.getStorableId())) {
          from = cell;
        }

        if (cell.getId().equals("v" + target.getStorableId())) {
          to = cell;
        }
      }

    }
    if (from == null || to == null)
      return;
    mxGraphAnalysis mga = mxGraphAnalysis.getInstance();
    Object[] path = mga.getShortestPath(currentGraph, from, to, new mxICostFunction() {

      @Override
      public double getCost(mxCellState state) {
        double length = 0;
        boolean attrExist = false;
        if (JGraphView.this.edgeAttributes.get(state.getCell()) == null)
          return Double.POSITIVE_INFINITY;
        for (StorableAttribute attr : JGraphView.this.edgeAttributes.get(state.getCell()).keySet()) {
          if (attrName.equals(attr.getName())) {
            length = Double.valueOf(attr.getValue());
            attrExist = true;
          }
        }
        if (!attrExist)
          return Double.POSITIVE_INFINITY;
        if (maximum)
          return 1 / length;
        else
          return length;
      }
    }, currentGraph.getChildEdges(parent).length, subGraph.isDirected());

    if (path.length > 0) {
      currentGraph.setSelectionCells(path);
    } else {
      VisualGraph.windowMessage.infoMessage("Critical path was not found between vertexes " + source.getId() + " to "
          + target.getId(), "Critical path messsage");
    }
    currentGraph.setSelectionCells(path);
  }

  public void showPaths(final StorableVertex source, final StorableVertex target) {
    ArrayList<Object> paths = findPath(source, target);
    if (paths != null && paths.size() > 0) {
      currentGraph.setSelectionCells(paths);
    } else {
      VisualGraph.windowMessage.infoMessage("Path was not found beetween vertexes " + source.getId() + " to " + target.getId(),
          "Path messsage");
    }
  }

  public void setSelectionElements(final List<Integer> lvsids, final List<Integer> lesids) {
    ArrayList<Object> selection = new ArrayList<Object>();
    Object parent = currentGraph.getDefaultParent();
    if (lvsids != null) {
      for (Object ob : currentGraph.getChildVertices(parent)) {
        if (ob instanceof mxCell) {
          mxCell cell = (mxCell) ob;
          int sid = Integer.parseInt(cell.getId().substring(1));
          for (Integer i : lvsids) {
            if (i.equals(sid)) {
              selection.add(cell);
              break;
            }
          }
        }
      }
    }
    if (lesids != null) {
      for (Object ob : currentGraph.getChildEdges(parent)) {
        if (ob instanceof mxCell) {
          mxCell cell = (mxCell) ob;
          int sid = Integer.parseInt(cell.getId().substring(1));
          for (Integer i : lesids) {
            if (i.equals(sid)) {
              selection.add(cell);
              break;
            }
          }
        }
      }
    }
    currentGraph.setSelectionCells(selection);
  }

  public String getTitle() {
    return (this.title);
  }

  @Override
  public void addNewConnect(int connectId, String connectName, String attributeName, int graphId) {
    if (graphId != this.graphId)
      return;
    Connection c = new Connection();
    c.connectId = connectId;
    c.connectName = connectName;
    c.attributeName = attributeName;
    this.connections.put(connectId, c);
  }

  @Override
  public void removeConnect(int connectId) {
    this.connections.remove(connectId);
  }

  // /////////////////////////////////////////////////////////////////////////
  // PRIVATE METHODS
  // /////////////////////////////////////////////////////////////////////////
  /**
   * This method creates shortName and fullName. Need: this.model, this.subgraph.
   */
  private void buildTitleAndGraphId() {
    if (this.subGraph != null && this.model != null) {
      List<StorableVertex> lsv = this.subGraph.getVertices();
      if (lsv != null && lsv.size() != 0) {
        // find subgraph id
        StorableVertex sv = lsv.get(0);
        // int gid = -1; // graph id
        int vid = sv.getStorableId(); // vertex id
        int sid = -1; // subgraph id
        String firstRequest = "select s1.db_id_subgraph " + "from com_subgraph_vertex s1 "
            + "where s1.db_id_vertex = " + Integer.valueOf(vid).toString() + ";";
        List<List<Object>> firstResult = this.model.executeSQLRequest(firstRequest);
        if (firstResult != null && !firstResult.isEmpty()) {
          sid = (Integer) firstResult.get(0).get(0);
        }

        // find graph id
        String thirdRequest = "select distinct s1.db_id_graph " + "from com_graph_subgraph s1 "
            + "where s1.db_id_subgraph = " + Integer.valueOf(sid) + ";";
        List<List<Object>> thirdResult = this.model.executeSQLRequest(thirdRequest);
        if (thirdResult != null && !thirdResult.isEmpty()) {
          this.graphId = (Integer) thirdResult.get(0).get(0);
        }
        // find vertex, which has innderId = sid
        if (sid >= 0) {
          String secondRequest = "select s1.db_id " + "from vertex s1 " + "where s1.db_id_inner_graph = "
              + Integer.valueOf(sid).toString() + ";";
          List<List<Object>> secondResult = this.model.executeSQLRequest(secondRequest);
          if (secondResult != null && !secondResult.isEmpty()) {
            int rid = (Integer) secondResult.get(0).get(0); // result id
            StorableVertex rsv = this.model.getStorableVertex(rid); // root storable vertex
            // find attribute 'name'
            List<StorableAttribute> lsa = rsv.getAttributes();
            if (lsa != null) {
              for (StorableAttribute bufSA : lsa) {
                if (bufSA.equals("name")) {
                  String value = bufSA.getValue();
                  if (value != null) {
                    this.title = bufSA.getValue() + " by name";
                  }
                  return;
                }
              }
            }
            // other find id of vertex
            String buf = rsv.getId();
            if (buf != null && buf.length() > 0) {
              this.title = buf + " by id";
              return;
            }
          } else {
            // it is root
            StorableSubGraph ssg = this.model.getStorableSubGraph(sid);
            String buf = ssg.getName();
            if (buf != null && buf.length() > 0) {
              this.title = buf + " by name";
              return;
            }
            buf = ssg.getId();
            if (buf != null && buf.length() > 0) {
              this.title = buf + " by id";
              return;
            }
          }
        }
      }
    }
    this.title = "Unknown";
  }

  private ArrayList<Object> findPath(final StorableVertex source, final StorableVertex target) {
    mxCell from = null;
    mxCell to = null;
    Object parent = currentGraph.getDefaultParent();
    Object[] cells = currentGraph.getChildVertices(parent);
    for (Object c : cells) {
      if (c instanceof mxCell) {
        mxCell cell = (mxCell) c;
        if (cell.getId().equals("v" + source.getStorableId())) {
          from = cell;
        }

        if (cell.getId().equals("v" + target.getStorableId())) {
          to = cell;
        }
      }

    }
    if (from == null || to == null)
      return null;

    ArrayList<Object> paths = new ArrayList<Object>();
    ArrayList<Object> visited = new ArrayList<Object>();
    dfs(from, to, paths, visited, null);
    paths.add(from);
    return paths;
  }

  private void dfs(final Object root, final Object target, List<Object> paths, List<Object> visited, Object prevEdge) {
    visited.add(root);
    Object[] e = (subGraph.isDirected()) ? currentGraph.getOutgoingEdges(root) : currentGraph.getConnections(root);
    if (e == null)
      return;
    for (Object edge : e) {
      if (edge.equals(prevEdge))
        continue;
      Object[] opp = currentGraph.getOpposites(new Object[] { edge }, root);

      if (opp != null && opp.length > 0) {
        Object o = opp[0];

        if (o.equals(target)) {
          paths.add(o);
          paths.add(edge);
        } else {
          if (visited.contains(o))
            continue;
          int l = paths.size();
          dfs(o, target, paths, visited, edge);
          if (l != paths.size()) {
            paths.add(edge);
            paths.add(o);
          }
        }
      }
    }
    visited.remove(root);
  }

  private void turnObservers() {
    Object[] arrLocal;
    synchronized (this.observers) {
      /*
       * We don't want the Observer doing callbacks into arbitrary code while holding its own Monitor. The code where we extract each
       * Observable from the Vector and store the state of the Observer needs synchronization, but notifying observers does not
       * (should not). The worst result of any potential race-condition here is that: 1) a newly-added Observer will miss a
       * notification in progress 2) a recently unregistered Observer will be wrongly notified when it doesn't care
       */
      arrLocal = this.observers.toArray();
    }
    for (int i = 0; i < arrLocal.length; i++) {
      ((Observer) arrLocal[i]).update(null, null);
    }
  }

  private mxIEventListener undoHandle = new mxIEventListener() {
    public void invoke(Object sender, mxEventObject evt) {
      undoManager.undoableEditHappened((mxUndoableEdit) evt.getProperty("edit"));
    }
  };

  private List<StorableEdge> getAllEdgesBeetweenVertexes(List<StorableVertex> vertexes) {
    List<StorableEdge> edges = new ArrayList<StorableEdge>();
    if (this.subGraph.getEdges() != null) {
      for (StorableEdge e : subGraph.getEdges()) {
        boolean s = false;
        boolean t = false;
        for (StorableVertex v : vertexes) {
          if (!s) {
            s = e.getStorableSource().getStorableId() == v.getStorableId();
          }
          if (!t) {
            t = e.getStorableTarget().getStorableId() == v.getStorableId();
          }
          if (s && t) {
            break;
          }
        }
        if (s && t) {
          edges.add(e);
        }
      }
    }
    return (edges);
  }

  // graph converter from Visual Graph format into jgraphx format
  private void loadGraph() {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
          JGraphView.this.loadGraph();
        }
      });
      return;
    }
    Object parent = currentGraph.getDefaultParent();

    List<StorableVertex> graphVertexes = subGraph.getVertices();
    List<StorableEdge> graphEdges = subGraph.getEdges();
    // loading graph from model
    currentGraph.getModel().beginUpdate();

    try {
      HashMap<StorableVertex, mxCell> v2v = new HashMap<StorableVertex, mxCell>();
      subgraphsid = new HashMap<mxCell, Integer>();
      // Vertexes load
      // TODO add id firstly should be in model

      if (graphVertexes != null) {
        for (int i = 0; i < graphVertexes.size(); i++) {
          mxCell vertex = (mxCell) currentGraph.insertVertex(parent,
              "v" + Integer.toString(graphVertexes.get(i).getStorableId()), "", 0, 0, 0, 0);

          vertex.setConnectable(false);

          currentGraph.updateCellSize(vertex);
          v2v.put(graphVertexes.get(i), vertex);

          Integer s = graphVertexes.get(i).getInnerGraph();
          if (s != null) {
            subgraphsid.put(vertex, s);
            vertex.setStyle(vertex.getStyle() + ";" + mxConstants.STYLE_FONTSTYLE + "=" + mxConstants.FONT_UNDERLINE + ";"
                + mxConstants.STYLE_FONTCOLOR + "=" + "blue");
          }
          HashMap<StorableAttribute, Boolean> attrs = new HashMap<StorableAttribute, Boolean>();
          for (StorableAttribute attr : graphVertexes.get(i).getAttributes()) {
            if (attr.getName().toLowerCase().compareTo("color") == 0)
              vertex.setStyle(vertex.getStyle() + ";" + mxConstants.STYLE_FILLCOLOR + "=" + attr.getValue());
            if (attr.getName().toLowerCase().compareTo("shape") == 0)
              vertex.setStyle(vertex.getStyle() + ";" + mxConstants.STYLE_SHAPE + "=" + attr.getValue());
            if (attr.getName().equalsIgnoreCase("name"))
              attrs.put(attr, new Boolean(true));
            else
              attrs.put(attr, new Boolean(false));
          }
          this.vertexAttributes.put(vertex, attrs);
        }
      }
      // Edges load
      boolean direction = subGraph.isDirected();

      if (graphEdges != null) {
        for (int i = 0; i < graphEdges.size(); i++) {

          mxCell edge = (mxCell) currentGraph.insertEdge(parent, "e" + Integer.toString(graphEdges.get(i).getStorableId()), "",
              v2v.get(graphEdges.get(i).getStorableSource()), v2v.get(graphEdges.get(i).getStorableTarget()));
          if (!direction)
            edge.setStyle(edge.getStyle() + ";" + mxConstants.STYLE_ENDARROW + "=" + mxConstants.NONE);

          HashMap<StorableAttribute, Boolean> attrs = new HashMap<StorableAttribute, Boolean>();
          for (StorableAttribute attr : graphEdges.get(i).getStorableAttributes()) {
            if (attr.getName().toLowerCase().compareTo("dashed") == 0)
              edge.setStyle(edge.getStyle() + ";" + mxConstants.STYLE_DASHED + "=" + attr.getValue());
            if (attr.getName().equalsIgnoreCase("name"))
              attrs.put(attr, new Boolean(true));
            else
              attrs.put(attr, new Boolean(false));
          }
          this.edgeAttributes.put(edge, attrs);
        }
      }
    } finally {
      currentGraph.getModel().endUpdate();
    }
    // Set default visual attributes----------
    HashSet<String> vertexAttr = new HashSet<String>();
    HashSet<String> edgeAttr = new HashSet<String>();
    vertexAttr.add("name");
    edgeAttr.add("name");
    showAttributes(vertexAttr, edgeAttr);
    // ---------------------------------------
    parent = currentGraph.getDefaultParent();

    executeLayout();
  }

  private void guiSetup() {
    if (!SwingUtilities.isEventDispatchThread()) {
      SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
          JGraphView.this.guiSetup();
        }
      });
      return;
    }

    graphComponent = new mxGraphComponent(currentGraph);

    graphComponent.setConnectable(false);
    graphComponent.setToolTips(true);
    graphComponent.setDragEnabled(false);
    graphComponent.setZoomFactor(2);
    // allow rubberband selection
    new mxRubberband(graphComponent);
    // allow use keyboard
    new mxKeyboardHandler(graphComponent);

    // minimap
    graphOutline = new mxGraphOutline(graphComponent);
    MouseWheelListener wheelTracker = new MouseWheelListener() {

      public void mouseWheelMoved(MouseWheelEvent e) {
        if (e.getSource() instanceof mxGraphOutline || e.isControlDown()) {
          if (e.getWheelRotation() < 0) {
            graphComponent.zoomIn();
          } else {
            graphComponent.zoomOut();
          }
        }

      }

    };
    graphOutline.addMouseWheelListener(wheelTracker);
    graphComponent.addMouseWheelListener(wheelTracker);

    mxIEventListener undoHandler = new mxIEventListener() {
      public void invoke(Object sender, mxEventObject evt) {
        List<mxUndoableChange> changes = ((mxUndoableEdit) evt.getProperty("edit")).getChanges();
        currentGraph.setSelectionCells(currentGraph.getSelectionCellsForChanges(changes));

      }
    };
    mxIEventListener selectHandler = new mxIEventListener() {
      public void invoke(Object sender, mxEventObject evt) {
        turnObservers();
      }
    };
    mxIEventListener moveHandler = new mxIEventListener() {
      public void invoke(Object sender, mxEventObject evt) {
        double x = 0, y = 0;
        for (Object o : (Object[]) evt.getProperty("cells")) {
          mxCell cell = (mxCell) o;
          if (cell.getGeometry().getX() < x)
            x = cell.getGeometry().getX();
          if (cell.getGeometry().getY() < y)
            y = cell.getGeometry().getY();
        }
        if (x != 0 || y != 0)
          currentGraph.moveCells(currentGraph.getChildCells(currentGraph.getDefaultParent()), -x, -y);
      }
    };
    undoManager.addListener(mxEvent.UNDO, undoHandler);
    undoManager.addListener(mxEvent.REDO, undoHandler);
    currentGraph.getSelectionModel().addListener(mxEvent.CHANGE, selectHandler);
    currentGraph.addListener(mxEvent.CELLS_MOVED, moveHandler);

    this.popup = new JPopupMenu();
    final JMenuItem openSubGraphMenuItem = new JMenuItem("Open subgraph in new tab");
    openSubGraphMenuItem.addActionListener(new ActionListener() {

      public void actionPerformed(ActionEvent arg0) {
        IGraphView view = JGraphView.this;
        IGraphView subgraph = new JGraphView(JGraphView.this, view.getSelectionSubGraph());
        if (!isSelected())
          return;

        UIRequestOpenSubGraph r = new UIRequestOpenSubGraph(subgraph, JGraphView.this.requestOwner);
        JGraphView.this.userInterface.addRequest(r);
      }
    });
    this.popup.add(openSubGraphMenuItem);
    this.connectorPopup = new JMenu("go to notepad");
    this.popup.add(connectorPopup);
    graphComponent.getGraphControl().addMouseListener(new MouseAdapter() {
      private void popupTriger(MouseEvent e) {
        if (e.isPopupTrigger()) {
          openSubGraphMenuItem.setEnabled(JGraphView.this.isSelected());

          mxCell cell = (mxCell) graphComponent.getCellAt(e.getX(), e.getY());
          if (cell != null) {
            connectorPopup.removeAll();

            for (final Connection con : connections.values()) {
              Set<StorableAttribute> attributes = null;
              if (cell.isVertex())
                attributes = vertexAttributes.get(cell).keySet();
              else if (cell.isEdge()) {
                attributes = edgeAttributes.get(cell).keySet();
              } else
                break;

              for (final StorableAttribute attr : attributes) {
                if (attr.getName().equals(con.attributeName)) {
                  JMenuItem item = new JMenuItem(con.connectName);
                  item.addActionListener(new ActionListener() {
                    public void actionPerformed(ActionEvent e) {
                      UIRequestGoToInAIF r = new UIRequestGoToInAIF(con.connectId, attr.getValue(),
                          JGraphView.this.requestOwner);
                      JGraphView.this.userInterface.addRequest(r);
                    }
                  });
                  connectorPopup.add(item);
                }
              }

            }
            connectorPopup.setEnabled(connectorPopup.getItemCount() > 0);
          } else {
            connectorPopup.setEnabled(false);
          }

          JGraphView.this.popup.show(e.getComponent(), e.getX(), e.getY());
        }
        SwingUtilities.updateComponentTreeUI(popup);
      }

      @Override
      public void mouseReleased(MouseEvent e) {
        if (e.getClickCount() > 1) {
          mxCell cell = (mxCell) graphComponent.getCellAt(e.getX(), e.getY());
          if (cell != null && subgraphsid.containsKey(cell)) {
            if (JGraphView.this.model != null) {
              StorableSubGraph ssg = JGraphView.this.model.getStorableSubGraph(subgraphsid.get(cell).intValue());
              IGraphView view = new JGraphView(ssg, JGraphView.this.userInterface);
              UIRequestOpenSubGraph r = new UIRequestOpenSubGraph(view, JGraphView.this.requestOwner);
              JGraphView.this.userInterface.addRequest(r);
            } else {
              VisualGraph.log.printError("[" + this.getClass().getName()
                  + ".JGraphView.mouseReleased] [BAD] Can't get storable subgraph, because model = null.");
            }
          }
        }
        popupTriger(e);
      }

      @Override
      public void mousePressed(MouseEvent e) {
        popupTriger(e);
      }
    });
  }
 
  protected void finalize() throws Throwable  {
    JGraphSettings.removeListner(settingListner);
    super.finalize();
  }

  private class Connection {
    private int connectId;
    private String connectName;
    private String attributeName;
  }

}
TOP

Related Classes of vg.userInterface.jgraphx.JGraphView

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.